<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script>
    // 实例化对象都有原型属性([[Prototype]]) => 指向构造函数(创建该实例化对象构造函数)的原型对象(prototype)
    // 构造函数 => 创建实例化对象
    function Cat(name, color) {
        // {}
        // {}[[Prototype]] = Cat.prototype   {}.__proto__ = Cat.prototype  => 所有的实例化对象都有原型属性([[Prototype]]) => 指向构造函数的原型对象(prototype)   !!!!!!!!
        // this -> {}   强制将this指向创建的实例化对象
        this.name = name
        this.color = color
        // return this
    }
    // protptype(原型对象 => 对象) => 存储所有实例化对象共有的属性和方法  => 供所有的实例化对象访问
    Cat.prototype.species = "Cat"
    Cat.prototype.call = function () {
        console.log("喵喵")
    }
    Cat.prototype.skill = function () {
        console.log("捉老鼠")
    }
    Cat.prototype.say = function () {
        // this指向 => 调用此方法的实例化对象
        console.log(this.name, this.color)
    }
    Object.prototype.a = 1
    Object.prototype.b = 2

    // 原型链 实例化对象属性和方法的链式查找机制
    // 1. 自己有就找自己的       // 2. 自己没有就顺着原型属性([[Prototype]]) => 找构造函数(创建该实例化对象的构造函数)的原型对象(Cat.prototype)
    // 3. 如果构造函数的原型对象(Cat.prototype)也找不到 => 到哪里找?  (到构造函数Object.prototype上查找)
    // 4. 如果构造函数Object的原型对象(Object.prototype)也找不到 => 不在向后查找

    // Tom -> Tom[[Prototype]] => Cat.prototype[[Prototype]] ->   null
    //        (Cat.prototype)     (Object.prototype)        // 所有的实例化对象都可以访问 Object.prototype上的属性和方法
    var Tom = new Cat("Tom", "black")
    console.log(Tom)

    // toString()   将实例化对象转化为字符串
    // valueOf()    返回实例化对象本身

    // console.log(Tom.toString())  // '[object Object]'
    // console.log(Tom.valueOf())   //  Tom


    // hasOwnProperty(key)  传入属性名,判断实例化对象是否存在该属性 (只查找实例化对象本身,不在原型链上查找)

    // console.log(Tom.hasOwnProperty("name"))  // true
    // console.log(Tom.hasOwnProperty("color")) // true

    // console.log(Tom.hasOwnProperty("species")) // false
    // console.log(Tom.hasOwnProperty("a"))  // false
    // console.log(Tom.hasOwnProperty("b"))  // false


    // 拓展: 如果向判断原型链上 是否存在某个属性名 =>  in
    // for (var key in 实例化对象) {
    //     console.log(key)
    // }

    // console.log("name" in Tom)
    // console.log("color" in Tom)
    // console.log("species" in Tom)
    // console.log("a" in Tom)
    // console.log("b" in Tom)
    // console.log("toString" in Tom)


    // isPrototypeOf()   判断某个构造函数的原型对象 => 是否于 某个实例化对象的原型链上

    // Tom的原型链:   Tom ->   Cat.prototype    =>   Object.prototype   => null
    // console.log(Cat.prototype.isPrototypeOf(Tom)) // true Cat.prototype 是否存在于 Tom 的原型链 上
    // console.log(Object.prototype.isPrototypeOf(Tom)) // true  Object.prototype 是否存在于 Tom 的原型链 上
    // console.log(Array.prototype.isPrototypeOf(Tom)) // false  Array.prototype 是否存在于 Tom 的原型链 上

    // 拓展(补充):
    // instanceof  判断 某个实例化对象 的原型链上 是否存在 某个构造函数 的原型对象
    // console.log(Tom instanceof Cat) //   Tom 的的原型链上是否存在构造函数 Cat 的原型对象  => true
    // console.log(Tom instanceof Object) // Tom 的的原型链上是否存在构造函数 Object 的原型对象  => true
    // propertyIsEnumerable()  传入属性名,判断实例化对象上该属性是否可以枚举(遍历)   (只查找实例化对象本身,不在原型链上查找)

    console.log(Tom.propertyIsEnumerable("name")) // true
    console.log(Tom.propertyIsEnumerable("color")) // true
    console.log(Tom.propertyIsEnumerable("species")) //false
    console.log(Tom.propertyIsEnumerable("a")) //false
    console.log(Tom.propertyIsEnumerable("b")) //false


</script>

</html>